package org.lisy.java.thread;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 计数器
 * 
 * @author lisy
 */
public class CountDownLatchOperate {

	/**
	 * await(): 等待计数器减为 0
	 * countDown(): 计数器减 1
	 * 技巧: 使用 CountDownLatch 同步计数器，当计数器数值减为 0 时，所有受其影响而等待的线程将会被激活，这样保证模拟并发请求的真实性
	 * 注意: CountDownLatch 是一次性的，计算器的值只能在构造方法中初始化一次，之后没有任何机制再次对其设置值，当 CountDownLatch 使用完毕后，它不能再次被使用 
	 */
	public static void main(String[] args) {
        ExecutorService service = Executors.newCachedThreadPool();
        final CountDownLatch cdOrder = new CountDownLatch(1);
        final CountDownLatch cdAnswer = new CountDownLatch(4);
        for (int i = 0; i < 4; i++) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println("player " + Thread.currentThread().getName() + " wait command ...");
                        cdOrder.await();
                        System.out.println("player " + Thread.currentThread().getName() + "receive command, start!");
                        Thread.sleep((long) (Math.random() * 10000));
                        System.out.println("player " + Thread.currentThread().getName() + " arrived!");
                        cdAnswer.countDown();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            };
            service.execute(runnable);
        }
        try {
        	TimeUnit.SECONDS.sleep(2);
            System.out.println("referee " + Thread.currentThread().getName() + " send command !");
            cdOrder.countDown();
            System.out.println("referee " + Thread.currentThread().getName() + " wait player arrived ...");
            cdAnswer.await();
            System.out.println("all player arrived!");
            System.out.println("referee " + Thread.currentThread().getName() + "release grade ranking!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        service.shutdown();
	}
	
}
